# xmlscenefunctions.py
#
# Functions to manipulate the xml scene objects

import xmlscene
from xmlscenereader import readScene

from list_functions import *
from math_functions import *
from vector_functions import *
from transformations import *

import math
import copy

def copyVertex(v):
    return xmlscene.vertex(x=v.x, y=v.y, z=v.z)

def vertexListForTriangle(triangle):
    return [triangle.vertex[0], triangle.vertex[1], triangle.vertex[2]]

def vectorListForVertex(v):
    return [v.x, v.y, v.z]

def vectorFromVertices(v0, v1):
    return map(subtract, vectorListForVertex(v0), vectorListForVertex(v1))

def distanceBetweenVertices(v0, v1):
    return magnitude(vectorFromVertices(v0, v1))

def centreOfVertices(v0, v1):
    centre = map(lambda p, q: average([p, q]), vectorListForVertex(v0), vectorListForVertex(v1))
    return xmlscene.vertex(x=centre[0], y=centre[1], z=centre[2])

def verticesEqual(v0, v1):
    return (v0.x == v1.x and v0.y == v1.y and v0.z == v1.z)

def triangleCentre(triangle):
    v = map(vectorListForVertex, vertexListForTriangle(triangle))
    centre = map(lambda p, q, r: average([p, q, r]), v[0], v[1], v[2])
    return centre

def triangleArea(triangle):
    # use Heron's area formula
    length = map(distanceBetweenVertices, vertexListForTriangle(triangle), shiftListLeft(vertexListForTriangle(triangle), 1))
    return heronsFormulaStable(length[0], length[1], length[2])

def divideTriangle(triangle):
    # returns 4 triangles that represent the divided triangle
    centre = shiftListLeft(map(centreOfVertices, vertexListForTriangle(triangle), shiftListLeft(vertexListForTriangle(triangle), 1)), 1)
    triangles = map(lambda t_v, c_2, c_1: xmlscene.triangle(vertex=[t_v, c_2, c_1]), 
                    triangle.vertex,
                    shiftListLeft(centre, 2),
                    shiftListLeft(centre, 1))
    triangles.append(xmlscene.triangle(vertex=[centre[0], centre[1], centre[2]]))
    return triangles

def zeroVertex():
    return xmlscene.vertex(x=0.0, y=0.0, z=0.0)

def zeroPolygon(num_points):
    return map(lambda index: zeroVertex(), xrange(num_points))

def extractRGBFromString(rgb_str):
    # should look like 'r,g,b'
    rgb = rgb_str.split(',')
    r = float(rgb[0])
    g = float(rgb[1])
    b = float(rgb[2])
    return [r, g, b]

def formatRGBAsString(r, g, b):
    # will create 'r,g,b'
    rgb_str = str(r) + ',' + str(g) + ',' + str(b)
    return rgb_str

def blackRGBString():
    return formatRGBAsString(0.0, 0.0, 0.0)

def isRGBStringBlack(rgb_str):
    rgb = extractRGBFromString(rgb_str)
    return (rgb[0] == 0.0 and rgb[1] == 0.0 and rgb[2] == 0.0)

def whiteRGBString():
    return formatRGBAsString(1.0, 1.0, 1.0)

def isRGBStringWhite(rgb_str):
    rgb = extractRGBFromString(rgb_str)
    return (rgb[0] == 1.0 and rgb[1] == 1.0 and rgb[2] == 1.0)

def isRGBStringGreaterThan(rgb_str0, rgb_str1):
    v0 = extractRGBFromString(rgb_str0)
    v1 = extractRGBFromString(rgb_str1)
    return (dotProduct(v0, v0) > dotProduct(v1, v1))

def areRGBStringsEqual(rgb_str0, rgb_str1):
    rgb0 = extractRGBFromString(rgb_str0)
    rgb1 = extractRGBFromString(rgb_str1)
    return (rgb0[0] == rgb1[0] and rgb0[1] == rgb1[1] and rgb0[2] == rgb1[2])

def operateOnRGBString(rgb_str, coefficient, binary_operator):
    new_rgb = map(lambda color: binary_operator(color, coefficient), extractRGBFromString(rgb_str))
    return formatRGBAsString(new_rgb[0], new_rgb[1], new_rgb[2])

def addToRGBString(rgb_str, constant):
    return operateOnRGBString(rgb_str, constant, add)

def multiplyRGBStringBy(rgb_str, constant):
    return operateOnRGBString(rgb_str, constant, multiply)

def divideRGBStringBy(rgb_str, constant):
    return operateOnRGBString(rgb_str, constant, divide)

def operateOnRGBStrings(rgb_str0, rgb_str1, binary_operator):
    rgb2 = map(binary_operator, extractRGBFromString(rgb_str0), extractRGBFromString(rgb_str1))
    return formatRGBAsString(rgb2[0], rgb2[1], rgb2[2])

def addRGBStrings(rgb_str0, rgb_str1):
    return operateOnRGBStrings(rgb_str0, rgb_str1, add)

def subtractRGBStrings(rgb_str0, rgb_str1):
    return operateOnRGBStrings(rgb_str0, rgb_str1, subtract)

def multiplyRGBStrings(rgb_str0, rgb_str1):
    return operateOnRGBStrings(rgb_str0, rgb_str1, multiply)

def divideRGBStrings(rgb_str0, rgb_str1):
    return operateOnRGBStrings(rgb_str0, rgb_str1, divide)

def vertexNormal(v0, v1, v2):
    u = vectorFromVertices(v1, v0)
    v = vectorFromVertices(v2, v0)
    return crossProduct3d(u, v)

def triangleNormal(triangle):
    return vertexNormal(triangle.vertex[0], triangle.vertex[1], triangle.vertex[2])

def objectdefForObject(xml_scene, object):
    for objectdef in xml_scene.get_head().get_objectdef():
        if objectdef.get_name() == object.get_name():
            return objectdef
    return None

def objectType(objectdef):
    if objectdef.get_triangleset() is not None:
        return xmlscene.triangleset
    if objectdef.get_cuboid() is not None:
        return xmlscene.cuboid
    if objectdef.get_barrel() is not None:
        return xmlscene.barrel
    if objectdef.get_globe() is not None:
        return xmlscene.globe
    if objectdef.get_teapot() is not None:
        return xmlscene.teapot
    return None

def objectDefObjects(objectdef):
    objects = []
    for triangleset in objectdef.get_triangleset():
        objects.append(triangleset)
    for cuboid in objectdef.get_cuboid():
        objects.append(cuboid)
    for barrel in objectdef.get_barrel():
        objects.append(barrel)
    for globe in objectdef.get_globe():
        objects.append(globe)
    for teapot in objectdef.get_teapot():
        objects.append(teapot)
    return objects

def transformationsForMacro(xml_scene, macro, child = None, curr_transformation = identityTransformationMatrix()):
    # recursively walk the transformations in the macro, adding
    # objects and transformations
    if child is None:
        child = macro
    if child is None: # child is still none
        return []

    this_calls_transformations = []

    if isinstance(child, xmlscene.apply_macro):
        return this_calls_transformations # apply_macros do nothing for object transformations

    # apply the current transformation to the object and create
    # a new [object, transformation] pair
    if not isinstance(child, xmlscene.macro) and len(child.get_object()) > 0:
        for object in child.get_object():
            object_transformation = numpy.matrix(curr_transformation)
            this_calls_transformations.append([object, object_transformation])

    # walk any transformations
    for translate in child.get_translate():
        trans_transformation = curr_transformation*translationMatrix(translate.dx, translate.dy, translate.dz)
        this_calls_transformations += transformationsForMacro(xml_scene, macro, translate, trans_transformation)
    for rotate in child.get_rotate():
        rotate_vector = [rotate.dx, rotate.dy, rotate.dz]
        rotate_angle = math.radians(rotate.angle)
        magn_rotate_vector = magnitude(rotate_vector)
        normalized_rotate_vector = [rotate_angle*rotate_vector[0]/magn_rotate_vector,
                                    rotate_angle*rotate_vector[1]/magn_rotate_vector,
                                    rotate_angle*rotate_vector[2]/magn_rotate_vector]
        # in rrv, they specify x and z angles right-handedly, and y angles left-handedly
        rot_transformation = curr_transformation*xRotationMatrix(theta=normalized_rotate_vector[0], right_handed=True)
        rot_transformation *= yRotationMatrix(theta=normalized_rotate_vector[1], right_handed=False)
        rot_transformation *= zRotationMatrix(theta=normalized_rotate_vector[2], right_handed=True)
        this_calls_transformations += transformationsForMacro(xml_scene, macro, rotate, rot_transformation)
    for scale in child.get_scale():
        scale_transformation = curr_transformation*scaleMatrix(scale.dx, scale.dy, scale.dz)
        this_calls_transformations += transformationsForMacro(xml_scene, macro, scale, scale_transformation)
    # TODO: for shear in child.shear:

    return this_calls_transformations

def applyMacros(xml_scene):
    objects_and_transformations = []
    for macro in xml_scene.get_body().get_macro():
        objects_and_transformations += transformationsForMacro(xml_scene, macro)
    return objects_and_transformations

def updateColorPeak(color_peak, color):
    c_r, c_g, c_b = extractRGBFromString(color)

    if color_peak < c_r:
        color_peak = c_r
    if color_peak < c_g:
        color_peak = c_g
    if color_peak < c_b:
        color_peak = c_b

    return color_peak

def normalize(color_peak, color):
    c_r, c_g, c_b = extractRGBFromString(color)

    ratio = 1.0/color_peak
    c_r *= ratio
    c_g *= ratio
    c_b *= ratio

    return formatRGBAsString(c_r, c_g, c_b)

def adjustEmissiveObjectRadiosity(objects):
    # if an object has emission, bump its radiosity up to at least 
    # that emission level
    for object in objects:
        if isRGBStringGreaterThan(object.get_emission(), object.get_radiosity()):
            object.set_radiosity(object.get_emission())

def initializeEmissiveObjectRadiosities(xml_scene):
    objectdefs = xml_scene.get_head().get_objectdef()
    map(lambda objectdef: adjustEmissiveObjectRadiosity(objectDefObjects(objectdef)), objectdefs)

if __name__ == '__main__':
    class TestXMLSceneFunctions(unittest.TestCase):

        def setUp(self):
            self.infile = "./xml_test_files/test_scene_xmlscene_functions.xml"
            self.inscene = readScene(self.infile)

        def test_vertex_list_for_triangle(self):
            v0 = xmlscene.vertex(x=0.0, y=1.0, z=2.0)
            v1 = xmlscene.vertex(x=8.4, y=-10.598, z=0.0)
            v2 = xmlscene.vertex(x=3.1415, y=0.0, z=-1000)
            triangle = xmlscene.triangle(vertex=[v0, v1, v2])
            self.assert_(vertexListForTriangle(triangle) == [v0, v1, v2])

        def test_vector_list_for_vertex(self):
            v = xmlscene.vertex(x=78.9, y=9485.209, z=-10.0234)
            self.assert_(vectorListForVertex(v) == [78.9, 9485.209, -10.0234])

        def test_vector_from_vertices(self):
            v0 = xmlscene.vertex(x=1.0, y=2.0, z=3.0)
            v1 = xmlscene.vertex(x=0.0, y=0.5, z=4.0)
            self.assert_(vectorFromVertices(v0, v1) == [1.0, 1.5, -1.0])

        def test_distance_between_vertices(self):
            v0 = xmlscene.vertex(x=1.0, y=2.0, z=3.0)
            v1 = xmlscene.vertex(x=2.3, y=1.0, z=1.0)
            self.assert_(distanceBetweenVertices(v0, v1) == magnitude([-1.3, 1.0, 2.0]))

        def test_vertices_equal(self):
            v0 = xmlscene.vertex(x=1.0, y=2.0, z=3.0)
            v1 = xmlscene.vertex(x=1.0, y=2.0, z=3.0)
            v2 = xmlscene.vertex(x=1.0, y=2.0, z=-3.0)
            self.assert_(verticesEqual(v0, v0))
            self.assert_(verticesEqual(v0, v1))
            self.assert_(verticesEqual(v1, v0))
            self.assert_(not verticesEqual(v0, v2))
            self.assert_(not verticesEqual(v2, v1))

        def test_vertex_centre(self):
            v0 = xmlscene.vertex(x=1.0, y=2.0, z=3.0)
            v1 = xmlscene.vertex(x=3.0, y=2.0, z=1.0)
            self.assert_(centreOfVertices(v0, v1).x == 2.0)
            self.assert_(centreOfVertices(v0, v1).y == 2.0)
            self.assert_(centreOfVertices(v0, v1).z == 2.0)

        def test_triangle_centre(self):
            v0 = xmlscene.vertex(x=0.0, y=0.0, z=0.0)
            v1 = xmlscene.vertex(x=1.0, y=2.0, z=10.0)
            v2 = xmlscene.vertex(x=2.0, y=-1.0, z=5.0)
            triangle = xmlscene.triangle(vertex=[v0, v1, v2])
            c = triangleCentre(triangle)
            self.assert_(c[0] == 1.0)
            self.assert_(c[1] == 1.0/3.0)
            self.assert_(c[2] == 5.0)

        def test_triangle_area(self):
            v0 = xmlscene.vertex(x=0.0, y=2.0, z=0.0)
            v1 = xmlscene.vertex(x=0.0, y=2.0, z=3.0)
            v2 = xmlscene.vertex(x=4.0, y=2.0, z=3.0)
            triangle = xmlscene.triangle(vertex=[v0, v1, v2])
            self.assert_(triangleArea(triangle) == 6.0)

        def test_divide_triangle(self):
            v0 = xmlscene.vertex(x=0.0, y=0.0, z=0.0)
            v1 = xmlscene.vertex(x=1.0, y=2.0, z=10.0)
            v2 = xmlscene.vertex(x=2.0, y=-1.0, z=5.0)
            triangle = xmlscene.triangle(vertex=[v0, v1, v2])
            triangles = divideTriangle(triangle)
            self.assert_(len(triangles) == 4)
            c01 = centreOfVertices(v0, v1)
            c12 = centreOfVertices(v1, v2)
            c20 = centreOfVertices(v2, v0)
            self.assert_(verticesEqual(triangles[0].vertex[0], v0))
            self.assert_(verticesEqual(triangles[0].vertex[1], c01))
            self.assert_(verticesEqual(triangles[0].vertex[2], c20))
            self.assert_(verticesEqual(triangles[1].vertex[0], v1))
            self.assert_(verticesEqual(triangles[1].vertex[1], c12))
            self.assert_(verticesEqual(triangles[1].vertex[2], c01))
            self.assert_(verticesEqual(triangles[2].vertex[0], v2))
            self.assert_(verticesEqual(triangles[2].vertex[1], c20))
            self.assert_(verticesEqual(triangles[2].vertex[2], c12))
            self.assert_(verticesEqual(triangles[3].vertex[0], c12))
            self.assert_(verticesEqual(triangles[3].vertex[1], c20))
            self.assert_(verticesEqual(triangles[3].vertex[2], c01))

        def test_zero_vertex(self):
            self.assert_(verticesEqual(zeroVertex(), xmlscene.vertex(x=0.0, y=0.0, z=0.0)))

        def test_zero_polygon(self):
            zero_triangle = zeroPolygon(3)
            self.assert_(verticesEqual(zero_triangle[0], zeroVertex()))
            self.assert_(verticesEqual(zero_triangle[1], zeroVertex()))
            self.assert_(verticesEqual(zero_triangle[2], zeroVertex()))

        def test_extract_RGB_from_string(self):
            rgb_str = "0.56, 0.008, 1.0"
            self.assert_(extractRGBFromString(rgb_str) == [0.56, 0.008, 1.0])

        def test_format_RGB_as_string(self):
            r = 0.02
            g = 1.00
            b = 0.00000
            self.assert_(formatRGBAsString(r, g, b) == "0.02,1.0,0.0")

        def test_black_RGB_string(self):
            self.assert_(blackRGBString() == "0.0,0.0,0.0")

        def test_is_RGB_string_black(self):
            self.assert_(isRGBStringBlack(blackRGBString()))

        def test_white_RGB_string(self):
            self.assert_(whiteRGBString() == "1.0,1.0,1.0")

        def test_is_RGB_string_greater_than(self):
            rgb_0 = "0.1,0.2,0.3"
            rgb_1 = "0.11,0.21,0.29"
            self.assert_(isRGBStringGreaterThan(rgb_1, rgb_0))
            self.assert_(not isRGBStringGreaterThan(rgb_0, rgb_1))

        def test_are_RGB_strings_equal(self):
            self.assert_(areRGBStringsEqual(blackRGBString(), blackRGBString()))
            self.assert_(not areRGBStringsEqual(whiteRGBString(), blackRGBString()))
            self.assert_(not areRGBStringsEqual(blackRGBString(), whiteRGBString()))

        def test_add_to_RGB_string(self):
            self.assert_(areRGBStringsEqual(addToRGBString(blackRGBString(), 1.0), whiteRGBString()))
            self.assert_(areRGBStringsEqual(addToRGBString("0.1,0.2,0.3", 0.25), "0.35,0.45,0.55"))

        def test_multiply_RGB_string_by(self):
            self.assert_(areRGBStringsEqual(multiplyRGBStringBy(whiteRGBString(), 1.0), whiteRGBString()))
            self.assert_(areRGBStringsEqual(multiplyRGBStringBy(whiteRGBString(), 0.5), "0.5,0.5,0.5"))
            self.assert_(areRGBStringsEqual(multiplyRGBStringBy("0.1,0.2,0.3", 0.1), "0.01,0.02,0.03"))

        def test_add_RGB_strings(self):
            self.assert_(areRGBStringsEqual(addRGBStrings(blackRGBString(), whiteRGBString()), whiteRGBString()))
            self.assert_(areRGBStringsEqual(addRGBStrings(blackRGBString(), blackRGBString()), blackRGBString()))
            self.assert_(areRGBStringsEqual(addRGBStrings("0.1,0.2,0.3", "0.65,0.123,0.7"), "0.75,0.323,1.0"))

        def test_multiply_RGB_strings(self):
            self.assert_(areRGBStringsEqual(multiplyRGBStrings(whiteRGBString(), whiteRGBString()), whiteRGBString()))
            self.assert_(areRGBStringsEqual(multiplyRGBStrings(whiteRGBString(), blackRGBString()), blackRGBString()))
            self.assert_(areRGBStringsEqual(multiplyRGBStrings("0.1,0.2,0.3", "0.3,0.2,0.1"), "0.03,0.04,0.03"))

        def test_vertex_normal(self):
            # TODO
            pass

        def test_triangle_normal(self):
            # TODO
            pass

        def test_transformations_for_macro(self):
            macros = self.inscene.get_body().get_macro()
            room_macro = None
            light_macro = None
            view_scene_macro = None
            scene_macro = None
            for macro in macros:
                if macro.get_name() == "room":
                    room_macro = macro
                elif macro.get_name() == "light":
                    light_macro = macro
                elif macro.get_name() == "viewScene":
                    view_scene_macro = macro
                elif macro.get_name() == "scene":
                    scene_macro = macro
            self.assert_(room_macro is not None)
            self.assert_(light_macro is not None)
            self.assert_(view_scene_macro is not None)
            self.assert_(scene_macro is not None)
            
            room_transformations = transformationsForMacro(self.inscene, room_macro) 
            self.assert_(len(room_transformations) == 6)
            xyplane_pair_1 = room_transformations[0]
            self.assert_(xyplane_pair_1[0].get_name() == "xyplane")
            xyplane_1_transform = xyplane_pair_1[1]
            xyplane_1_actual = translationMatrix(10.0, 0.0, 0.0)
            xyplane_1_actual *= yRotationMatrix(math.radians(90.0))
            truth = (xyplane_1_transform == xyplane_1_actual)
            self.assert_(truth.all())
            xyplane_pair_2 = room_transformations[1]
            self.assert_(xyplane_pair_2[0].get_name() == "xyplane")
            xyplane_2_transform = xyplane_pair_2[1]
            xyplane_2_actual = translationMatrix(-10.0, 0.0, 0.0)
            xyplane_2_actual *= yRotationMatrix(-math.radians(90.0))
            truth = (xyplane_2_transform == xyplane_2_actual)
            self.assert_(truth.all())
            xyplane_pair_3 = room_transformations[2]
            self.assert_(xyplane_pair_3[0].get_name() == "xyplane")
            xyplane_3_transform = xyplane_pair_3[1]
            xyplane_3_actual = translationMatrix(0.0, 0.0, -10.0)
            truth = (xyplane_3_transform == xyplane_3_actual)
            self.assert_(truth.all())
            xyplane_pair_4 = room_transformations[3]
            self.assert_(xyplane_pair_4[0].get_name() == "xyplane")
            xyplane_4_transform = xyplane_pair_4[1]
            xyplane_4_actual = translationMatrix(0.0, 0.0, 10.0)
            xyplane_4_actual *= yRotationMatrix(math.radians(180.0))
            truth = (xyplane_4_transform == xyplane_4_actual)
            self.assert_(truth.all())
            xyplane_pair_5 = room_transformations[4]
            self.assert_(xyplane_pair_5[0].get_name() == "xyplane")
            xyplane_5_transform = xyplane_pair_5[1]
            xyplane_5_actual = translationMatrix(0.0, 10.0, 0.0)
            xyplane_5_actual *= xRotationMatrix(math.radians(90.0))
            truth = (xyplane_5_transform == xyplane_5_actual)
            self.assert_(truth.all())
            xyplane_green_pair = room_transformations[5]
            self.assert_(xyplane_green_pair[0].get_name() == "xyplane-green")
            xyplane_green_transform = xyplane_green_pair[1]
            xyplane_green_actual = translationMatrix(0.0, -10.0, 0.0)
            xyplane_green_actual *= xRotationMatrix(-math.radians(90.0))
            truth = (xyplane_green_transform == xyplane_green_actual)
            self.assert_(truth.all())
            
            light_transformations = transformationsForMacro(self.inscene, light_macro)
            self.assert_(len(light_transformations) == 3)
            black_barrel_pair_1 = light_transformations[0]
            self.assert_(black_barrel_pair_1[0].get_name() == "black-barrel")
            black_barrel_1_transform = black_barrel_pair_1[1]
            black_barrel_1_actual = translationMatrix(-1.5, 2.0, 0.0)
            black_barrel_1_actual *= scaleMatrix(1.0, 4.0, 1.0)
            truth = (black_barrel_1_transform == black_barrel_1_actual)
            self.assert_(truth.all())
            black_barrel_pair_2 = light_transformations[1]
            self.assert_(black_barrel_pair_2[0].get_name() == "black-barrel")
            black_barrel_2_transform = black_barrel_pair_2[1]
            black_barrel_2_actual = translationMatrix(1.5, 2.0, 0.0)
            black_barrel_2_actual *= scaleMatrix(1.0, 4.0, 1.0)
            truth = (black_barrel_2_transform == black_barrel_2_actual)
            self.assert_(truth.all())
            light_source_pair = light_transformations[2]
            self.assert_(light_source_pair[0].get_name() == "light-source")
            light_source_transform = light_source_pair[1]
            light_source_actual = translationMatrix(0.0, -1.0, 0.0)
            light_source_actual *= scaleMatrix(6.0, 2.0, 4.0)
            truth = (light_source_transform == light_source_actual)
            self.assert_(truth.all())
            
            scene_transformations = transformationsForMacro(self.inscene, scene_macro)
            self.assert_(len(scene_transformations) == 13)
            light_1_overall = translationMatrix(0.0, 6.0, 4.0)
            self.assert_(scene_transformations[0][0].get_name() == "black-barrel")
            truth = (light_1_overall*translationMatrix(-1.5, 2.0, 0.0)*scaleMatrix(1.0, 4.0, 1.0) == scene_transformations[0][1])
            self.assert_(truth.all())
            self.assert_(scene_transformations[1][0].get_name() == "black-barrel")
            truth = (light_1_overall*translationMatrix(1.5, 2.0, 0.0)*scaleMatrix(1.0, 4.0, 1.0) == scene_transformations[1][1])
            self.assert_(truth.all())
            self.assert_(scene_transformations[2][0].get_name() == "light-source")
            truth = (light_1_overall*translationMatrix(0.0, -1.0, 0.0)*scaleMatrix(6.0, 2.0, 4.0) == scene_transformations[2][1])
            self.assert_(truth.all())
            light_2_overall = translationMatrix(0.0, 6.0, -4.0)
            self.assert_(scene_transformations[3][0].get_name() == "black-barrel")
            truth = (light_2_overall*translationMatrix(-1.5, 2.0, 0.0)*scaleMatrix(1.0, 4.0, 1.0) == scene_transformations[3][1])
            self.assert_(truth.all())
            self.assert_(scene_transformations[4][0].get_name() == "black-barrel")
            truth = (light_2_overall*translationMatrix(1.5, 2.0, 0.0)*scaleMatrix(1.0, 4.0, 1.0) == scene_transformations[4][1])
            self.assert_(truth.all())
            self.assert_(scene_transformations[5][0].get_name() == "light-source")
            truth = (light_2_overall*translationMatrix(0.0, -1.0, 0.0)*scaleMatrix(6.0, 2.0, 4.0) == scene_transformations[5][1])
            self.assert_(scene_transformations[6][0].get_name() == "teapot")
            teapot_actual = translationMatrix(0.0, -8.0, 5.0)
            teapot_actual *= yRotationMatrix(-math.radians(45.0))
            teapot_actual *= scaleMatrix(2.0, 2.0, 2.0)
            truth = (scene_transformations[6][1] == teapot_actual)
            self.assert_(truth.all())
            self.assert_(scene_transformations[7][0].get_name() == "xyplane")
            xyplane_1_actual = translationMatrix(10.0, 0.0, 0.0)
            xyplane_1_actual *= yRotationMatrix(math.radians(90.0))
            truth = (scene_transformations[7][1] == xyplane_1_actual)
            self.assert_(truth.all())
            self.assert_(scene_transformations[8][0].get_name() == "xyplane")
            xyplane_2_actual = translationMatrix(-10.0, 0.0, 0.0)
            xyplane_2_actual *= yRotationMatrix(-math.radians(90.0))
            truth = (scene_transformations[8][1] == xyplane_2_actual)
            self.assert_(truth.all())
            self.assert_(scene_transformations[9][0].get_name() == "xyplane")
            xyplane_3_actual = translationMatrix(0.0, 0.0, -10.0)
            truth = (scene_transformations[9][1] == xyplane_3_actual)
            self.assert_(truth.all())
            self.assert_(scene_transformations[10][0].get_name() == "xyplane")
            xyplane_4_actual = translationMatrix(0.0, 0.0, 10.0)
            xyplane_4_actual *= yRotationMatrix(math.radians(180.0))
            truth = (scene_transformations[10][1] == xyplane_4_actual)
            self.assert_(truth.all())
            self.assert_(scene_transformations[11][0].get_name() == "xyplane")
            xyplane_5_actual = translationMatrix(0.0, 10.0, 0.0)
            xyplane_5_actual *= xRotationMatrix(math.radians(90.0))
            truth = (scene_transformations[11][1] == xyplane_5_actual)
            self.assert_(truth.all())
            self.assert_(scene_transformations[12][0].get_name() == "xyplane-green")
            xyplane_green_actual = translationMatrix(0.0, -10.0, 0.0)
            xyplane_green_actual *= xRotationMatrix(-math.radians(90.0))
            truth = (scene_transformations[12][1] == xyplane_green_actual)
            self.assert_(truth.all())
            
        def test_apply_macros(self):
            transformations = applyMacros(self.inscene)
            self.assert_(len(transformations) == 13)
            view_scene_overall = translationMatrix(-2.0, 0.0, 0.0)
            view_scene_overall *= yRotationMatrix(math.radians(60.0))
            view_scene_overall *= scaleMatrix(1.5, 1.5, 1.8)
            light_1_overall = view_scene_overall*translationMatrix(0.0, 6.0, 4.0)
            self.assert_(transformations[0][0].get_name() == "black-barrel")
            truth = (light_1_overall*translationMatrix(-1.5, 2.0, 0.0)*scaleMatrix(1.0, 4.0, 1.0) == transformations[0][1])
            self.assert_(truth.all())
            self.assert_(transformations[1][0].get_name() == "black-barrel")
            truth = (light_1_overall*translationMatrix(1.5, 2.0, 0.0)*scaleMatrix(1.0, 4.0, 1.0) == transformations[1][1])
            self.assert_(truth.all())
            self.assert_(transformations[2][0].get_name() == "light-source")
            truth = (light_1_overall*translationMatrix(0.0, -1.0, 0.0)*scaleMatrix(6.0, 2.0, 4.0) == transformations[2][1])
            self.assert_(truth.all())
            light_2_overall = view_scene_overall*translationMatrix(0.0, 6.0, -4.0)
            self.assert_(transformations[3][0].get_name() == "black-barrel")
            truth = (light_2_overall*translationMatrix(-1.5, 2.0, 0.0)*scaleMatrix(1.0, 4.0, 1.0) == transformations[3][1])
            self.assert_(truth.all())
            self.assert_(transformations[4][0].get_name() == "black-barrel")
            truth = (light_2_overall*translationMatrix(1.5, 2.0, 0.0)*scaleMatrix(1.0, 4.0, 1.0) == transformations[4][1])
            self.assert_(truth.all())
            self.assert_(transformations[5][0].get_name() == "light-source")
            truth = (light_2_overall*translationMatrix(0.0, -1.0, 0.0)*scaleMatrix(6.0, 2.0, 4.0) == transformations[5][1])
            self.assert_(transformations[6][0].get_name() == "teapot")
            teapot_actual = view_scene_overall*translationMatrix(0.0, -8.0, 5.0)
            teapot_actual *= yRotationMatrix(-math.radians(45.0))
            teapot_actual *= scaleMatrix(2.0, 2.0, 2.0)
            truth = (transformations[6][1] == teapot_actual)
            self.assert_(truth.all())
            self.assert_(transformations[7][0].get_name() == "xyplane")
            xyplane_1_actual = view_scene_overall*translationMatrix(10.0, 0.0, 0.0)
            xyplane_1_actual *= yRotationMatrix(math.radians(90.0))
            truth = (transformations[7][1] == xyplane_1_actual)
            self.assert_(truth.all())
            self.assert_(transformations[8][0].get_name() == "xyplane")
            xyplane_2_actual = view_scene_overall*translationMatrix(-10.0, 0.0, 0.0)
            xyplane_2_actual *= yRotationMatrix(-math.radians(90.0))
            truth = (transformations[8][1] == xyplane_2_actual)
            self.assert_(truth.all())
            self.assert_(transformations[9][0].get_name() == "xyplane")
            xyplane_3_actual = view_scene_overall*translationMatrix(0.0, 0.0, -10.0)
            truth = (transformations[9][1] == xyplane_3_actual)
            self.assert_(truth.all())
            self.assert_(transformations[10][0].get_name() == "xyplane")
            xyplane_4_actual = view_scene_overall*translationMatrix(0.0, 0.0, 10.0)
            xyplane_4_actual *= yRotationMatrix(math.radians(180.0))
            truth = (transformations[10][1] == xyplane_4_actual)
            self.assert_(truth.all())
            self.assert_(transformations[11][0].get_name() == "xyplane")
            xyplane_5_actual = view_scene_overall*translationMatrix(0.0, 10.0, 0.0)
            xyplane_5_actual *= xRotationMatrix(math.radians(90.0))
            truth = (transformations[11][1] == xyplane_5_actual)
            self.assert_(truth.all())
            self.assert_(transformations[12][0].get_name() == "xyplane-green")
            xyplane_green_actual = view_scene_overall*translationMatrix(0.0, -10.0, 0.0)
            xyplane_green_actual *= xRotationMatrix(-math.radians(90.0))
            truth = (transformations[12][1] == xyplane_green_actual)
            self.assert_(truth.all())
            
    unittest.main()
